{
 "cells": [
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "1. 模型构建\n",
    "1.1 内容描述\n",
    "构建OCR识别模型。\n",
    "1.2 代码编写"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "from captcha_func import *\n",
    "# 定义CNN\n",
    "def crack_captcha_cnn(w_alpha=0.1, b_alpha=0.1):\n",
    "    x = tf.reshape(X, shape=[-1, IMAGE_HEIGHT, IMAGE_WIDTH, 1])\n",
    "\n",
    "    # 3 conv layer\n",
    "    w_c1 = tf.Variable(w_alpha * tf.random_normal([3, 3, 1, 32]))\n",
    "    b_c1 = tf.Variable(b_alpha * tf.random_normal([32]))\n",
    "    conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(x, w_c1, strides=[1, 1, 1, 1], padding='SAME'), b_c1))\n",
    "    conv1 = tf.nn.max_pool(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')\n",
    "    #conv1 = tf.nn.dropout(conv1, keep_prob)\n",
    "\n",
    "    w_c2 = tf.Variable(w_alpha * tf.random_normal([3, 3, 32, 64]))\n",
    "    b_c2 = tf.Variable(b_alpha * tf.random_normal([64]))\n",
    "    conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv1, w_c2, strides=[1, 1, 1, 1], padding='SAME'), b_c2))\n",
    "    conv2 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')\n",
    "    #conv2 = tf.nn.dropout(conv2, keep_prob)\n",
    "\n",
    "    w_c3 = tf.Variable(w_alpha * tf.random_normal([3, 3, 64, 64]))\n",
    "    b_c3 = tf.Variable(b_alpha * tf.random_normal([64]))\n",
    "    conv3 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(conv2, w_c3, strides=[1, 1, 1, 1], padding='SAME'), b_c3))\n",
    "    conv3 = tf.nn.max_pool(conv3, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')\n",
    "    #conv3 = tf.nn.dropout(conv3, keep_prob)\n",
    "\n",
    "    # Fully connected layer\n",
    "    # 获取conv3的shape\n",
    "    conv3_shape=conv3.get_shape().as_list()\n",
    "    w_d = tf.Variable(w_alpha * tf.random_normal([conv3_shape[1]*conv3_shape[2]*conv3_shape[3], 2048]))\n",
    "    b_d = tf.Variable(b_alpha * tf.random_normal([2048]))\n",
    "    dense = tf.reshape(conv3, [-1, w_d.get_shape().as_list()[0]])\n",
    "    dense = tf.nn.relu(tf.add(tf.matmul(dense, w_d), b_d))\n",
    "    dense = tf.nn.dropout(dense, keep_prob)\n",
    "    \n",
    "    w_d_2 = tf.Variable(w_alpha * tf.random_normal([2048, 512]))\n",
    "    b_d_2 = tf.Variable(b_alpha * tf.random_normal([512]))\n",
    "    dense_2 = tf.nn.relu(tf.add(tf.matmul(dense, w_d_2), b_d_2))\n",
    "    dense_2 = tf.nn.dropout(dense_2, keep_prob)\n",
    "\n",
    "    w_out = tf.Variable(w_alpha * tf.random_normal([512, MAX_CAPTCHA * CHAR_SET_LEN]))\n",
    "    b_out = tf.Variable(b_alpha * tf.random_normal([MAX_CAPTCHA * CHAR_SET_LEN]))\n",
    "    out = tf.add(tf.matmul(dense_2, w_out), b_out,name='out')\n",
    "    return out\n"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "2. 模型训练\n",
    "2.1 内容描述\n",
    "引用captcha_func文件，调用模型，定义损失函数、优化器以及准确率，并执行模型训练及模型保存阶段。\n",
    "2.2 代码编写"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 训练\n",
    "def train_crack_captcha_cnn():\n",
    "    #CNN 训练过程\n",
    "    output = crack_captcha_cnn()\n",
    "    #损失函数\n",
    "    loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=output, labels=Y),name='loss')\n",
    "    learning_rate=0.01\n",
    "    global_step=tf.Variable(0,trainable=False)\n",
    "    lr=tf.train.exponential_decay(learning_rate, global_step, 1000, 0.96, staircase=True,name='learning_rate')\n",
    "    #Adam函数\n",
    "    optimizer = tf.train.AdamOptimizer(learning_rate=lr).minimize(loss,global_step,name='optimizer')\n",
    "    #转换矩阵形状\n",
    "    predict = tf.reshape(output, [-1, MAX_CAPTCHA, CHAR_SET_LEN])\n",
    "    max_idx_p = tf.argmax(predict, 2)\n",
    "    max_idx_l = tf.argmax(tf.reshape(Y, [-1, MAX_CAPTCHA, CHAR_SET_LEN]), 2)\n",
    "    #相等的判断\n",
    "    correct_pred = tf.equal(max_idx_p, max_idx_l)\n",
    "    accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32),name='accuracy')\n",
    "\n",
    "    saver = tf.train.Saver()\n",
    "    with tf.Session() as sess:\n",
    "        sess.run(tf.global_variables_initializer())\n",
    "        ckpt = tf.train.get_checkpoint_state('captcha_model')\n",
    "        if ckpt and ckpt.model_checkpoint_path:\n",
    "            checkpoint_path = ckpt.model_checkpoint_path\n",
    "            saver.restore(sess, checkpoint_path)\n",
    "        step = 0\n",
    "        while True:\n",
    "            batch_x, batch_y = get_next_batch(32)\n",
    "            sess.run(optimizer, feed_dict={X: batch_x, Y: batch_y, keep_prob: 0.85})\n",
    "\n",
    "\n",
    "            # 每10 step计算一次准确率\n",
    "            if step % 100 == 0:\n",
    "                saver.save(sess, \"captcha_model/crack_capcha.model\")\n",
    "                batch_x_test, batch_y_test = get_next_batch(64)\n",
    "                acc,loss_ = sess.run([accuracy, loss], feed_dict={X: batch_x_test, Y: batch_y_test, keep_prob: 1.})\n",
    "                print(step, loss_)\n",
    "                print(step, acc)\n",
    "                print('*'*100)\n",
    "                # 如果准确率大于75%,保存模型,完成训练\n",
    "                if acc > 0.99:\n",
    "                    #持久化\n",
    "                    saver.save(sess, \"captcha_model/crack_capcha.model\")\n",
    "                    break\n",
    "\n",
    "            step += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "验证码图像channel: (60, 160, 3)\n",
      "验证码文本最长字符数 4\n",
      "WARNING:tensorflow:From <ipython-input-1-02e28be06f81>:31: calling dropout (from tensorflow.python.ops.nn_ops) with keep_prob is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Please use `rate` instead of `keep_prob`. Rate should be set to `rate = 1 - keep_prob`.\n",
      "WARNING:tensorflow:From C:\\ProgramData\\Anaconda3\\envs\\tf14\\lib\\site-packages\\tensorflow\\python\\ops\\nn_impl.py:180: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.where in 2.0, which has the same broadcast rule as np.where\n",
      "0 4.052533\n",
      "0 0.09375\n",
      "****************************************************************************************************\n",
      "100 0.32617846\n",
      "100 0.1015625\n",
      "****************************************************************************************************\n",
      "200 0.31909916\n",
      "200 0.1640625\n",
      "****************************************************************************************************\n",
      "300 0.27622095\n",
      "300 0.359375\n",
      "****************************************************************************************************\n",
      "400 0.22566167\n",
      "400 0.54296875\n",
      "****************************************************************************************************\n",
      "500 0.19654043\n",
      "500 0.58984375\n",
      "****************************************************************************************************\n",
      "600 0.18252556\n",
      "600 0.66796875\n",
      "****************************************************************************************************\n",
      "700 0.16775246\n",
      "700 0.69140625\n",
      "****************************************************************************************************\n",
      "800 0.14839137\n",
      "800 0.73828125\n",
      "****************************************************************************************************\n",
      "900 0.14484791\n",
      "900 0.71875\n",
      "****************************************************************************************************\n",
      "1000 0.1252841\n",
      "1000 0.80859375\n",
      "****************************************************************************************************\n",
      "1100 0.124461845\n",
      "1100 0.78125\n",
      "****************************************************************************************************\n",
      "1200 0.11212854\n",
      "1200 0.83984375\n",
      "****************************************************************************************************\n",
      "1300 0.096738435\n",
      "1300 0.85546875\n",
      "****************************************************************************************************\n",
      "1400 0.10891465\n",
      "1400 0.8359375\n",
      "****************************************************************************************************\n",
      "1500 0.10124163\n",
      "1500 0.86328125\n",
      "****************************************************************************************************\n",
      "1600 0.10371961\n",
      "1600 0.8359375\n",
      "****************************************************************************************************\n",
      "1700 0.10927323\n",
      "1700 0.828125\n",
      "****************************************************************************************************\n",
      "1800 0.08416926\n",
      "1800 0.85546875\n",
      "****************************************************************************************************\n",
      "1900 0.08084156\n",
      "1900 0.87109375\n",
      "****************************************************************************************************\n",
      "2000 0.07897127\n",
      "2000 0.85546875\n",
      "****************************************************************************************************\n",
      "2100 0.081882395\n",
      "2100 0.8828125\n",
      "****************************************************************************************************\n",
      "2200 0.056393147\n",
      "2200 0.92578125\n",
      "****************************************************************************************************\n",
      "2300 0.06553179\n",
      "2300 0.90625\n",
      "****************************************************************************************************\n",
      "2400 0.053409845\n",
      "2400 0.9375\n",
      "****************************************************************************************************\n",
      "2500 0.06127336\n",
      "2500 0.91796875\n",
      "****************************************************************************************************\n",
      "2600 0.049045727\n",
      "2600 0.9453125\n",
      "****************************************************************************************************\n",
      "2700 0.05943514\n",
      "2700 0.90234375\n",
      "****************************************************************************************************\n",
      "2800 0.03741888\n",
      "2800 0.9765625\n",
      "****************************************************************************************************\n",
      "2900 0.03323102\n",
      "2900 0.98046875\n",
      "****************************************************************************************************\n",
      "3000 0.039945945\n",
      "3000 0.94921875\n",
      "****************************************************************************************************\n",
      "3100 0.04599908\n",
      "3100 0.93359375\n",
      "****************************************************************************************************\n",
      "3200 0.038563717\n",
      "3200 0.95703125\n",
      "****************************************************************************************************\n",
      "3300 0.041239113\n",
      "3300 0.9375\n",
      "****************************************************************************************************\n",
      "3400 0.036123008\n",
      "3400 0.94921875\n",
      "****************************************************************************************************\n",
      "3500 0.034563214\n",
      "3500 0.953125\n",
      "****************************************************************************************************\n",
      "3600 0.04065197\n",
      "3600 0.94921875\n",
      "****************************************************************************************************\n",
      "3700 0.031630524\n",
      "3700 0.97265625\n",
      "****************************************************************************************************\n",
      "3800 0.04045844\n",
      "3800 0.94140625\n",
      "****************************************************************************************************\n",
      "3900 0.034063447\n",
      "3900 0.953125\n",
      "****************************************************************************************************\n",
      "4000 0.031925775\n",
      "4000 0.94921875\n",
      "****************************************************************************************************\n",
      "4100 0.023233537\n",
      "4100 0.98046875\n",
      "****************************************************************************************************\n",
      "4200 0.022980396\n",
      "4200 0.98046875\n",
      "****************************************************************************************************\n",
      "4300 0.026232993\n",
      "4300 0.9765625\n",
      "****************************************************************************************************\n",
      "4400 0.024783144\n",
      "4400 0.96875\n",
      "****************************************************************************************************\n",
      "4500 0.027014265\n",
      "4500 0.96875\n",
      "****************************************************************************************************\n",
      "4600 0.01687706\n",
      "4600 0.98828125\n",
      "****************************************************************************************************\n",
      "4700 0.024060473\n",
      "4700 0.9609375\n",
      "****************************************************************************************************\n",
      "4800 0.017109513\n",
      "4800 0.9765625\n",
      "****************************************************************************************************\n",
      "4900 0.020043202\n",
      "4900 0.96484375\n",
      "****************************************************************************************************\n",
      "5000 0.024763454\n",
      "5000 0.9765625\n",
      "****************************************************************************************************\n",
      "5100 0.019251619\n",
      "5100 0.9765625\n",
      "****************************************************************************************************\n",
      "5200 0.02274981\n",
      "5200 0.96875\n",
      "****************************************************************************************************\n",
      "5300 0.015070917\n",
      "5300 0.9765625\n",
      "****************************************************************************************************\n",
      "5400 0.025183931\n",
      "5400 0.96484375\n",
      "****************************************************************************************************\n",
      "5500 0.017181579\n",
      "5500 0.9765625\n",
      "****************************************************************************************************\n",
      "5600 0.017697314\n",
      "5600 0.984375\n",
      "****************************************************************************************************\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5700 0.022642875\n",
      "5700 0.96875\n",
      "****************************************************************************************************\n",
      "5800 0.018964265\n",
      "5800 0.97265625\n",
      "****************************************************************************************************\n",
      "5900 0.020533875\n",
      "5900 0.97265625\n",
      "****************************************************************************************************\n",
      "6000 0.021587338\n",
      "6000 0.9765625\n",
      "****************************************************************************************************\n",
      "6100 0.017474007\n",
      "6100 0.98046875\n",
      "****************************************************************************************************\n",
      "6200 0.012426576\n",
      "6200 0.98046875\n",
      "****************************************************************************************************\n",
      "6300 0.012769316\n",
      "6300 0.98828125\n",
      "****************************************************************************************************\n",
      "6400 0.027140517\n",
      "6400 0.95703125\n",
      "****************************************************************************************************\n",
      "6500 0.009119101\n",
      "6500 0.984375\n",
      "****************************************************************************************************\n",
      "6600 0.014025298\n",
      "6600 0.984375\n",
      "****************************************************************************************************\n",
      "6700 0.018296719\n",
      "6700 0.98828125\n",
      "****************************************************************************************************\n",
      "6800 0.01649782\n",
      "6800 0.98046875\n",
      "****************************************************************************************************\n",
      "6900 0.008565602\n",
      "6900 0.98828125\n",
      "****************************************************************************************************\n",
      "7000 0.015460625\n",
      "7000 0.98046875\n",
      "****************************************************************************************************\n",
      "7100 0.0057570166\n",
      "7100 0.9921875\n",
      "****************************************************************************************************\n"
     ]
    }
   ],
   "source": [
    "if __name__ == '__main__':\n",
    "\t#生成验证码值和图片\n",
    "\ttext, image = gen_captcha_text_and_image()\n",
    "\tprint(\"验证码图像channel:\", image.shape)  # (60, 160, 3)\n",
    "\tprint(\"验证码文本最长字符数\", MAX_CAPTCHA)\n",
    "\n",
    "\tX = tf.placeholder(tf.float32, [None, IMAGE_HEIGHT * IMAGE_WIDTH],name='X')\n",
    "\tY = tf.placeholder(tf.float32, [None, MAX_CAPTCHA * CHAR_SET_LEN],name='Y')\n",
    "\tkeep_prob = tf.placeholder(tf.float32,name='keep_prob')  # dropout\n",
    "\ttrain_crack_captcha_cnn()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
